#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <cmath>

typedef unsigned char BYTE;

int b64ti(char data)
{
	char *base64_set = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	unsigned int i;
	for(i=0; i<64; i++)
	{
		if(data==base64_set[i]) return i;
	}
}

void base64(char *data, char *out, int size) 
{
	unsigned int i, j=0;
	char *base64_set = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	for(i=0; i<size; (i+=3, j+=4))
	{
		if(data[i]=='\0') return;
		out[j]=base64_set[data[i]>>2];
		out[j+1]=base64_set[((data[i]&3)<<4)+(data[i+1]>>4)];
		if(data[i+1]=='\0')
		{
			out[j+2]='=';
			out[j+3]='=';
			out[j+4]=0;
			return;
		}
		out[j+2]=base64_set[((data[i+1]&15)<<2)+(data[i+2]>>6)];
		if(data[i+2]=='\0')
		{
			out[j+3]='=';
			out[j+4]=0;
			return;
		}
		out[j+3]=base64_set[data[i+2]&63];
		out[j+4]=0;
	}
}

unsigned int base64_encode(BYTE *data, BYTE *out, unsigned int size) 
{
	unsigned int i, j=0;
	char *base64_set = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	for(i=0; i<size; (i+=3, j+=4))
	{
		if(i==size-2)
		{
			out[j]=base64_set[data[i]>>2];
			out[j+1]=base64_set[((data[i]&3)<<4)|(data[i+1]>>4)];
			out[j+2]=base64_set[(data[i+1]&15)<<2];
			out[j+3]='=';
			return j+4;
		}
		else
		{
			if(i==size-1)
			{
				out[j]=base64_set[data[i]>>2];
				out[j+1]=base64_set[(data[i]&3)<<4];
				out[j+2]='=';
				out[j+3]='=';
				return j+3;
			}
			else
			{
				out[j]=base64_set[data[i]>>2];
				out[j+1]=base64_set[((data[i]&3)<<4)|(data[i+1]>>4)];
				out[j+2]=base64_set[((data[i+1]&15)<<2)|(data[i+2]>>6)];
				out[j+3]=base64_set[data[i+2]&63];
			}
		}
	}
	return j;
}

unsigned int base64_decode(BYTE *data, BYTE *out, unsigned int size, int _b64ti[]) 
{
	unsigned int i, j=0;
	char *base64_set = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	for(i=0; i<size; (i+=4, j+=3))
	{
		out[j]=(_b64ti[data[i]]<<2)|(_b64ti[data[i+1]]>>4);
		if(data[i+3]==data[i+2]=='=')
		{
			out[j+1]=0;
			return j+2;
		}
		out[j+1]=((_b64ti[data[i+1]]&15)<<4)|(_b64ti[data[i+2]]>>2);
		if(data[i+3]=='=')
		{
			out[j+2]=0;
			return j+1;
		}
		out[j+2]=((_b64ti[data[i+2]]&3)<<6)|_b64ti[data[i+3]];
		out[j+3]=0;
	}
	return j;
}

void inputString(const char * prompt, char * input)
{
        input[0] = 0;
        printf("%s", prompt);
        scanf("%[^\n]", input);
        fflush(stdin);
}

void main(int argc, char * argv[])
{
	FILE *inFile = NULL, *outFile = NULL;
	int input=1;
	char inputfile[100]="";
	char outputfile[100]="";
	char *base64_set = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	int _b64ti[256];
	unsigned int i, r, j, size;
	BYTE* data=NULL;
	BYTE* out=NULL;
	if(argc==1)
	{
		inputString("Enter input file name: ", inputfile);
		inputString("Enter output file name: ", outputfile);
		printf("Input '1' for encoding or '2'for decoding: ");
		scanf("%d", &r);
	}
	else
	{
		if(argc==4)
		{
			strcpy(inputfile, argv[2]);
			strcpy(outputfile, argv[3]);
			if(!strcmp(argv[1], "-e"))
			{
				r=1;
			}
			else if(!strcmp(argv[1], "-d"))
			{
				r=2;
			}
			else
			{
				printf("Wrong arguments! Restart app and try again!\n");
				system("PAUSE");
				return;
			}
		}
		else
		{
			printf("Wrong arguments! Restart app and try again!\n");
			system("PAUSE");
			return;
		}
	}
	if(r==1)
	{
		inFile = fopen(inputfile, "rb");
		outFile = fopen(outputfile, "w");
		if((inFile==NULL)||(outFile==NULL))
		{
			printf("Wrong arguments! Restart app and try again!\n");
			system("PAUSE");
			return;
		}
		for(i=0; fgetc(inFile)!=EOF; i++);
		rewind(inFile);
		size=i;
		data = (BYTE*)malloc(sizeof(char)*i);
		for(i=0; i<size; i++)
		{
			data[i]=fgetc(inFile);
		}
		fclose(inFile);
		r = ceil(size/3)*4+1;
		out = (BYTE*)malloc(sizeof(char)*r);
		r = base64_encode(data, out, size);
		for(i=0; i<r; i++)
		{
			fputc(out[i], outFile);
		}
		fclose(outFile);
    }
	if(r==2)
	{
		for(i=0; i<256; i++)
		{
			_b64ti[i]=-1;
		}
		for(i=0; i<64; i++)
		{
			_b64ti[base64_set[i]]=i;
		}
		inFile = fopen(inputfile, "r");
		outFile = fopen(outputfile, "wb");
		if((inFile==NULL)||(outFile==NULL))
		{
			printf("Wrong arguments! Restart app and try again!\n");
			system("PAUSE");
			return;
		}
		for(i=0; fgetc(inFile)!=EOF; i++);
		rewind(inFile);
		size=i;
		data = (BYTE*)malloc(sizeof(char)*i);
		for(i=0; i<size; i++)
		{
			data[i]=fgetc(inFile);
		}
		fclose(inFile);
		out = (BYTE*)malloc(sizeof(char)*size);
		size=base64_decode(data, out, size, _b64ti);
		for(i=0; i<size; i++)
		{
			fputc(out[i], outFile);
		}
		fclose(outFile);
    }
}